#include <QCoreApplication>
#include <QtNetwork/QHostAddress>
#include <QtNetwork/QUdpSocket>
#include <QReadWriteLock>
#include <QReadLocker>
#include <QWriteLocker>
#include <QDebug>
#include <QThread>
#include <QVariant>
#include <QSettings>
#include <QNetworkInterface>

#define MESSAGE "HTCK_DEVICE"
#define CAT(A,B) A##B
class Discovery : public QObject {
    Q_OBJECT

    QReadWriteLock _readWriteLock;
    std::atomic<bool> _stop=false;
    std::map<std::string,int> _ips;
public:
    Discovery() {
        QThread *workerThread = new QThread;
        QObject::connect(workerThread, &QThread::started, this, &Discovery::doWork);
        this->moveToThread(workerThread);
        workerThread->start();
    }
    ~Discovery() {_stop=true;}
    std::string getips(){
        std::string ips;
        {
            QReadLocker lock(&_readWriteLock);
            std::for_each(_ips.begin(),_ips.end(),[&](std::pair<const std::string,int>& it){ ips+="{\"ip\":\""+it.first+"\"},";});
        }
        return ips.substr(0,ips.size()-1);
    }
public slots:
    void doWork() {
        QUdpSocket socket;
        QSettings settings("config.ini", QSettings::IniFormat);
        if (!socket.bind(QHostAddress::AnyIPv4, 9001)) {
            qDebug() << "Failed to bind socket";
            return;
        }
        socket.setSocketOption(QAbstractSocket::MulticastTtlOption,1);
        socket.setSocketOption(QAbstractSocket::SocketOption::KeepAliveOption, QVariant(true));
        QHostAddress multicastAddress("224.0.0.1");
        quint16 multicastPort = 9001;
        if (!socket.joinMulticastGroup(multicastAddress)) {
            qDebug() << "Failed to join multicast group";
            return;
        }
        while (!_stop) {
            QByteArray sendgram(MESSAGE);
            sendgram.append(":");
            sendgram.append(settings.value("http/port", 80).toByteArray());
            sendgram.append("_");
            sendgram.append(settings.value("device/type", "1").toByteArray());
            socket.writeDatagram(sendgram,multicastAddress,multicastPort);
            QThread::sleep(1);

            qint64 recv_len;
            quint16 senderPort;
            QHostAddress senderAddress;
            do{
                QByteArray datagram("",socket.pendingDatagramSize());
                recv_len = socket.readDatagram(datagram.data(), datagram.size(), &senderAddress, &senderPort);
                if(datagram.startsWith(MESSAGE)){
                    std::string ip = senderAddress.toString().toStdString()+datagram.mid(strlen(MESSAGE)).data();
                    QWriteLocker lock(&_readWriteLock);
                    if(_ips.find(ip)==_ips.end())
                        qDebug()<<"add device:"<<ip;
                    _ips[ip]=10;
                }
            }while(recv_len>0);
            {
                QWriteLocker lock(&_readWriteLock);
                for(auto it=_ips.begin();it!=_ips.end();){
                    (*it).second--;
                    if ((*it).second==0){
                        qDebug()<<"delete device:"<<(*it).first;
                        it = _ips.erase(it);
                    }
                    else
                        it++;
                }
            }
        }
        socket.leaveMulticastGroup(multicastAddress);
        socket.abort();
    }
};